package ec.linde.modulos.dao;

import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import ec.linde.enumeraciones.Estado;
import ec.linde.persistencia.entidades.proyectos.CronogramaPlanOperativo;
import ec.linde.persistencia.entidades.proyectos.DetallePlanOperativo;
import ec.linde.persistencia.entidades.proyectos.PlanOperativo;

/**
 * TODO: Agregar descripcion
 * 
 * @FechaCreacion: 29/09/2014
 * @author: Alex Carrillo
 * @FechaModificacion: 29/09/2014
 * @author: Alex Carrillo
 * @version: 1.0
 */
@Stateless
public class PlanOperativoDao extends AbstractDao<PlanOperativo> {
	/**
	 * Constructor por defecto que inicializa el AbstractDao con la clase ProdPlanOperativo
	 */
	public PlanOperativoDao() {
		super(PlanOperativo.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.asinfo.as2.dao.AbstractDaoAS2#obtenerListaPorPagina(int, int, java.lang.String, boolean, java.util.Map)
	 */
	public List<PlanOperativo> obtenerListaPorPagina(int startIndex, int pageSize, String sortField, boolean sortOrder, Map<String, String> filters) {
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<PlanOperativo> criteriaQuery = criteriaBuilder.createQuery(PlanOperativo.class);
		Root<PlanOperativo> from = criteriaQuery.from(PlanOperativo.class);
		from.fetch("proyecto", JoinType.LEFT);
		from.fetch("rdo", JoinType.LEFT);

		final List<Expression<?>> expresiones = obtenerExpresiones(filters, criteriaBuilder, from);
		criteriaQuery.where(expresiones.toArray(new Predicate[expresiones.size()]));

		agregarOrdenamiento(sortField, sortOrder, criteriaBuilder, criteriaQuery, from);

		CriteriaQuery<PlanOperativo> select = criteriaQuery.select(from);
		TypedQuery<PlanOperativo> typedQuery = em.createQuery(select);
		agregarPaginacion(startIndex, pageSize, typedQuery);

		return typedQuery.getResultList();
	}

	/**
	 * Carga ProdPlanOperativo
	 * 
	 * @param idPlanOperativo
	 * @return ProdPlanOperativo
	 */
	public PlanOperativo cargarDetalle(int idPlanOperativo) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

		CriteriaQuery<PlanOperativo> cqCabecera = criteriaBuilder.createQuery(PlanOperativo.class);
		Root<PlanOperativo> fromCabecera = cqCabecera.from(PlanOperativo.class);
		Fetch<Object, Object> proyecto = fromCabecera.fetch("proyecto", JoinType.LEFT);

		proyecto.fetch("usuario", JoinType.LEFT);
		proyecto.fetch("persona", JoinType.LEFT);
		proyecto.fetch("cliente", JoinType.LEFT);
		proyecto.fetch("sucursal", JoinType.LEFT);
		proyecto.fetch("contactoCliente", JoinType.LEFT);
		proyecto.fetch("contratista", JoinType.LEFT);
		proyecto.fetch("contactoContratista", JoinType.LEFT);

		Path<Integer> pathId = fromCabecera.get("idPlanOperativo");
		cqCabecera.where(criteriaBuilder.equal(pathId, idPlanOperativo));
		CriteriaQuery<PlanOperativo> selectPlanOperativo = cqCabecera.select(fromCabecera);
		PlanOperativo planOperativo = em.createQuery(selectPlanOperativo).getSingleResult();

		// Carga el detalle de las proformas Secundarias
		CriteriaQuery<DetallePlanOperativo> cqDetallePlanOperativo = criteriaBuilder.createQuery(DetallePlanOperativo.class);
		Root<DetallePlanOperativo> fromDetallePlanOperativo = cqDetallePlanOperativo.from(DetallePlanOperativo.class);
		fromDetallePlanOperativo.fetch("partida", JoinType.LEFT);
		fromDetallePlanOperativo.fetch("concepto", JoinType.LEFT);
		cqDetallePlanOperativo.where(criteriaBuilder.equal(fromDetallePlanOperativo.join("planOperativo"), planOperativo));
		CriteriaQuery<DetallePlanOperativo> selectDetallePlanOperativo = cqDetallePlanOperativo.select(fromDetallePlanOperativo);

		List<DetallePlanOperativo> listaDetallePlanOperativo = em.createQuery(selectDetallePlanOperativo).getResultList();
		planOperativo.setListaDetallePlanOperativo(listaDetallePlanOperativo);

		// Carga el cronograma
		for (DetallePlanOperativo detallePlanOperativo : listaDetallePlanOperativo) {

			em.detach(detallePlanOperativo);
			detallePlanOperativo.setPlanOperativo(planOperativo);

			CriteriaQuery<CronogramaPlanOperativo> cqCronograma = criteriaBuilder.createQuery(CronogramaPlanOperativo.class);
			Root<CronogramaPlanOperativo> fromCronograma = cqCronograma.from(CronogramaPlanOperativo.class);
			cqCronograma.where(criteriaBuilder.equal(fromCronograma.join("detallePlanOperativo"), detallePlanOperativo));
			CriteriaQuery<CronogramaPlanOperativo> selectCronograma = cqCronograma.select(fromCronograma);
			List<CronogramaPlanOperativo> listaCronogramaPlanOperativo = em.createQuery(selectCronograma).getResultList();
			detallePlanOperativo.setListaCronogramaPlanOperativo(listaCronogramaPlanOperativo);

			for (CronogramaPlanOperativo cronogramaPlanOperativo : listaCronogramaPlanOperativo) {
				em.detach(cronogramaPlanOperativo);
				cronogramaPlanOperativo.setDetallePlanOperativo(detallePlanOperativo);
			}

		}

		return planOperativo;
	}

	@SuppressWarnings("unchecked")
	public PlanOperativo obtenerPlanOperativoActivo(Integer idProyecto) {

		StringBuilder sql = new StringBuilder();
		sql.append(" SELECT MAX(po.version), po.idPlanOperativo ");
		sql.append(" FROM  PlanOperativo	po ");
		sql.append(" INNER JOIN po.proyecto py ");
		sql.append(" WHERE py.idProyecto =:idProyecto ");
		sql.append(" GROUP BY po.idPlanOperativo ");
		sql.append(" ORDER BY po.version DESC ");

		Query query = em.createQuery(sql.toString());
		query.setParameter("idProyecto", idProyecto);
		query.setMaxResults(1);
		List<Object[]> lista = query.getResultList();

		Integer idPlanOperativo = 0;
		for (Object[] object : lista) {
			idPlanOperativo = (Integer) object[1];
		}

		if (idPlanOperativo != 0) {
			return buscarPorId(idPlanOperativo);
		} else {
			return null;
		}

	}

	public void cambiarEstado(int idPlanOperativo, Estado estado) {
		Query query = em.createQuery("UPDATE PlanOperativo po SET po.estado = :estado WHERE po.idPlanOperativo = :idPlanOperativo");
		query.setParameter("estado", estado);
		query.setParameter("idPlanOperativo", idPlanOperativo);
		query.executeUpdate();
	}

	public void cambiarEstadoPlanOperativoAnteriores(PlanOperativo planOperativo, Estado estado) {
		Query query = em
				.createQuery("UPDATE PlanOperativo po SET po.estado = :estado WHERE po.proyecto = :proyecto AND po.idPlanOperativo != :idPlanOperativo ");
		query.setParameter("estado", estado);
		query.setParameter("proyecto", planOperativo.getProyecto());
		query.setParameter("idPlanOperativo", planOperativo.getIdPlanOperativo());
		query.executeUpdate();
	}
}
